#include "stinger.h"
#include "build_type.h"

//把name转换为物理id
int name_to_phy_id(std::string name) {
    //return xor_hash((uint8_t*)name.data(), name.length()) % VERTEX_NUM;
    return bkdr_hash((char*)name.data());
} 

//根据物理id找到逻辑id,没有物理id则返回-1.
int phy_id_to_logical_id(int phy_id) {
    hashmap::const_accessor acc;
    bool res = stinger_root->mapper->find(acc, phy_id);

    if (res) {
        assert(acc->first == phy_id);
        const pmem::obj::p<int> *logical_id = &acc->second;
        return *logical_id;
    } else {
        return -1;
    }
}

/*
添加一个顶点
如果顶点的类型不存在返回：-1
如果顶点已经在了，不需要插入：0
成功插入返回：1
*/
int insert_vertex(std::string vertex_name, std::string type, int weight = 1, int inDegree = 0, int outDegree = 0) {
    //判断添加的顶点的类型是否存在
    int vertex_type = get_vertex_type_mapping(type);
    if (vertex_type == -1) {
        return -1;
    }
    int id = name_to_phy_id(type + "_" + vertex_name);
    int logical_id = phy_id_to_logical_id(id);
    if (logical_id != -1) {
        return 0;
    }

    struct stinger_vertex vertex(id, vertex_name, vertex_type, weight, inDegree, outDegree);
    stinger_root->logical_vertex_array.vertices[stinger_root->logical_vertex_array.max_vertices] = vertex;
    
    //添加物理顶点id到逻辑顶点id的映射，可以把max_vertices视为逻辑顶点的id
    stinger_root->mapper->insert_or_assign(id, stinger_root->logical_vertex_array.max_vertices);

    stinger_root->logical_vertex_array.max_vertices.get_rw() += 1;

    return 1;
}

//根据name获取一个顶点
stinger_vertex* get_vertex(std::string vertex_name, std::string type) {

    int vertex_type = get_vertex_type_mapping(type);

    int id = name_to_phy_id(type + "_" + vertex_name);
    
    hashmap::const_accessor acc;
    bool res = stinger_root->mapper->find(acc, id);

    if (res) {
        assert(acc->first == id);
        const pmem::obj::p<int>* logical_id = &acc->second;
        struct stinger_vertex *vertex = &stinger_root->logical_vertex_array.vertices[*logical_id];
        return vertex;
    }
    return nullptr;
}

//根据物理id获得一个顶点
stinger_vertex* get_vertex_by_phy_id(int phy_id) {

    hashmap::const_accessor acc;
    bool res = stinger_root->mapper->find(acc, phy_id);

    if (res) {
        assert(acc->first == phy_id);
        const pmem::obj::p<int>* logical_id = &acc->second;
        struct stinger_vertex *vertex = &stinger_root->logical_vertex_array.vertices[*logical_id];
        return vertex;
    }
    return nullptr;
}

/*
更新顶点的weight、inDegree、outDegree三个值，如果所传入的值 小于0，表示不更新这一项。
返回值为0表示，需要更新的顶点不存在，
返回值为1表示，更新成功
*/

int update_vertex_by_phy_id(int phy_id, int weight = -1, int inDegree = -1, int outDegree = -1) {
    int logical_id = phy_id_to_logical_id(phy_id);
    // 需要更新的顶点不存在
    if (logical_id == -1) return 0;
    
    struct stinger_vertex *vertex = get_vertex_by_phy_id(phy_id);
    if (weight >= 0) vertex->weight.get_rw() = weight;
    if (inDegree >= 0) vertex->inDegree.get_rw() = inDegree;
    if (outDegree >= 0) vertex->outDegree.get_rw() = outDegree;
    
    return 1;
}

int update_vertex_by_name(std::string vertex_name, std::string type, int weight = -1, int inDegree = -1, int outDegree = -1) {
    int vertex_phy_id = name_to_phy_id(type + "_" + vertex_name);
    return update_vertex_by_phy_id(vertex_phy_id, weight, inDegree, outDegree);
}

//顶点的属性值自增x，传入参数为x表示自增x，传入参数为0表示不修改
int vertex_self_increase_by_phy_id(int phy_id, int weight = 0, int inDegree = 0, int outDegree = 0) {
    int logical_id = phy_id_to_logical_id(phy_id);
    // 需要更新的顶点不存在
    if (logical_id == -1) return 0;
    
    struct stinger_vertex *vertex = get_vertex_by_phy_id(phy_id);
    if (weight != 0) vertex->weight.get_rw() = vertex->weight + weight;
    if (inDegree != 0) vertex->inDegree.get_rw() = vertex->inDegree + inDegree;
    if (outDegree != 0) vertex->outDegree.get_rw() = vertex->outDegree + outDegree;
    
    

    return 1;
}
int vertex_self_increase_by_name(std::string vertex_name, std::string type, int weight = 0, int inDegree = 0, int outDegree = 0) {
    int vertex_phy_id = name_to_phy_id(type + "_" + vertex_name);
    return vertex_self_increase_by_phy_id(vertex_phy_id, weight, inDegree, outDegree);
}

//释放一个顶点的边块链表的空间，需要循环释放，如果顶点不存在返回0，释放成功返回1
int free_eb_list_by_phy_id(int phy_id) {
    int logical_id = phy_id_to_logical_id(phy_id);
    // 需要更新的顶点不存在
    if (logical_id == -1) return 0;

    struct stinger_vertex *vertex = get_vertex_by_phy_id(phy_id);
    //遍历这个顶点的整个边块链表，得到它的所有的出点，更新其入度。
    pmem::obj::persistent_ptr<stinger_eb> edge_block_ptr = vertex->edge_block_ptr;

    if (edge_block_ptr == nullptr) return 1;
    pmem::obj::persistent_ptr<stinger_eb> next_eb_ptr = nullptr;
    pmem::obj::transaction::run(pop, [&] {
        while (1) {
            if (edge_block_ptr == nullptr) {
                break;
            } else {
                next_eb_ptr = edge_block_ptr->next_edge_block_ptr;
                pmem::obj::delete_persistent<stinger_eb>(edge_block_ptr);
                
                edge_block_ptr = next_eb_ptr;
            }
        }
    });
    vertex->edge_block_ptr = nullptr;
    return 1;

}

int free_eb_list_by_name(std::string vertex_name, std::string type) {
    int vertex_phy_id = name_to_phy_id(type + "_" + vertex_name);
    return free_eb_list_by_phy_id(vertex_phy_id);
}


//根据顶点的物理ID，删除一个顶点
bool delete_vertex_by_phy_id(int phy_id) {
    /*首先判断这个定点是否存在，如果不存在就不需要删除*/
    int logical_id = phy_id_to_logical_id(phy_id);
    if (logical_id == -1) {
        //这个顶点本来就存在，不用删除
        return true;
    } else {
        /*1. 移除out edge
        需要释放整个边块链表的空间，与该顶点相连的顶点的入度-1，或者出度-1
        */
        struct stinger_vertex *vertex = get_vertex_by_phy_id(phy_id);

        //遍历这个顶点的整个边块链表，得到它的所有的出点，更新其入度。
        pmem::obj::persistent_ptr<stinger_eb> edge_block_ptr = vertex->edge_block_ptr;

        while (1) {
            if (edge_block_ptr == nullptr) {
                break;
            } else {
                for (int i = 0; i < edge_block_ptr->high; i++) {
                    if (edge_block_ptr->edges[i].neighbor != -1) {
                        //更新出点的入度
                        int res = vertex_self_increase_by_phy_id(edge_block_ptr->edges[i].neighbor, 0, -1, 0);
                        assert(res == 1);
                    }
                }
                edge_block_ptr = edge_block_ptr->next_edge_block_ptr;
            }
        }


        //释放空间
        free_eb_list_by_phy_id(phy_id);
        

        //更新与之相连的顶点的出度，要遍历所有的顶点的边块链表（相当于遍历了所有的边）
        //??一个顶点的出度等于所有边块的有效边的数量累加和

        /*2. 移除in edge

        */

        if (vertex->inDegree > 0) {
            //需要遍历所有类型的所有的边
            for (int i = 0; i < stinger_root->logical_vertex_array.max_vertices; i++) {
                struct stinger_vertex *traversal_vertex = &stinger_root->logical_vertex_array.vertices[i];

                if (traversal_vertex->outDegree > 0 && traversal_vertex->id != -1) {
                    pmem::obj::persistent_ptr<stinger_eb> edge_block_ptr_ = traversal_vertex->edge_block_ptr;
                    int break_flag = 0;
                    while (1) {
                        if (edge_block_ptr_ == nullptr) {
                            break;
                        } else {
                            for (int j = 0; j < edge_block_ptr_->high; j++) {
                                if (edge_block_ptr_->edges[j].neighbor == phy_id) {
                                    //std::cout << "name = " << traversal_vertex->name << std::endl;
                                    
                                    traversal_vertex->outDegree.get_rw() = traversal_vertex->outDegree - 1;
                                    edge_block_ptr_->edges[j].neighbor.get_rw() = -1;
                                    edge_block_ptr_->numEdges.get_rw() = edge_block_ptr_->numEdges - 1;

                                    //std::cout << "outd = " << traversal_vertex->outDegree << std::endl;

                                    break_flag = 1;
                                    break;
                                }
                            }
                            if (break_flag == 1) break;
                            edge_block_ptr_ = edge_block_ptr_->next_edge_block_ptr;
                        }
                    }
                }
            }
        }
        /*
        for (int i = 0; i < 10; i++) {
            struct stinger_vertex *vertex1 = get_vertex("Jerry" + std::to_string(i), "user");
            assert(vertex1 != nullptr);
            std::cout << "Jerry" << std::to_string(i) << "的出度 = " << vertex1->outDegree << std::endl;
        }
        */

        /*3. 将逻辑顶点数组中的物理顶点id置为-1，表示该entry无效*/
        vertex->id.get_rw() = -1;

        /*4. 从物理映射 mapper 里面删除*/
        stinger_root->mapper->erase(phy_id);
        
        return true;
    }

}

//根据顶点的name，删除一个顶点
bool delete_vertex_by_name(std::string vertex_name, std::string type) {
    int vertex_phy_id = name_to_phy_id(type + "_" + vertex_name);
    return delete_vertex_by_phy_id(vertex_phy_id);
}



